package cn.dduan.fool.design.pattern.behavior.strategy;

/**
 * 策略模式
 * <p>
 * 概念：将类中经常改变或者可能改变的部分提取为作为一个抽象策略接口类，然后在类中包含这个对象的实例，这样类实例在运行时就可以随意调用实现了这个接口的类的行为
 * <p>
 * 优点：
 * 1、可以动态改变对象的行为
 * <p>
 * 缺点：
 * 1、但缺点是会产生很多策略类，同时客户端必须知道所有的策略类，并自行决定使用哪一个策略类
 * <p>
 * 应用场景：
 * 1、应用程序需要实现特定的功能服务，而该程序有多种实现方式使用，所以需要动态地在几种算法中选择一种
 * 2、一个类定义了多种行为算法，并且这些行为在类的操作中以多个条件语句的形式出现，就可以将相关的条件分支移入它们各自的Strategy类中以代替这些条件语句
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/10
 */
public class StrategyPattern {
    public static void main(String[] args) {
        Context context;

        System.out.println("----------刚到吴国使用第一个锦囊---------------");
        context = new Context(new BackDoor());
        context.operate();
        System.out.println();

        System.out.println("----------刘备乐不思蜀使用第二个锦囊---------------");
        context.setStrategy(new GivenGreenLight());
        context.operate();
        System.out.println();

        System.out.println("----------孙权的追兵来了，使用第三个锦囊---------------");
        context.setStrategy(new BlackEnemy());
        context.operate();
        System.out.println();
    }
}

/**
 * 抽象策略类
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/10
 */
interface Strategy {
    public void operate();
}

/**
 * 具体实现：妙计一：初到吴国
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/10
 */
class BackDoor implements Strategy {
    @Override
    public void operate() {
        System.out.println("找乔国老帮忙，让吴国太给孙权施加压力，使孙权不能杀刘备");
    }
}

/**
 * 具体实现：妙计二：求吴国太开绿灯放行
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/10
 */
class GivenGreenLight implements Strategy {
    @Override
    public void operate() {
        System.out.println("求吴国太开个绿灯，放行");
    }
}

/**
 * 具体实现：妙计三：孙夫人断后，挡住追兵
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/10
 */
class BlackEnemy implements Strategy {
    @Override
    public void operate() {
        System.out.println("孙夫人断后，挡住追兵");
    }
}

/**
 * 环境类
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/10
 */
class Context {
    private Strategy strategy;

    //构造函数，要你使用哪个妙计
    public Context(Strategy strategy) {
        this.strategy = strategy;
    }

    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }

    public void operate() {
        this.strategy.operate();
    }
}